package com.techstar.mqttprocesser.service.mqtt.config;

import com.alibaba.fastjson.JSON;
import com.techstar.mqttprocesser.service.mqtt.handler.MqttServiceRegistry;
import com.techstar.mqttprocesser.service.mqtt.handler.message.MessageHandler;
import com.techstar.mqttprocesser.service.mqtt.handler.message.MessageHandlerFactory;
import org.eclipse.paho.client.mqttv3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;

/**
 * @author lilei
 * @create 2025-03-27-2025/3/27
 */
@Configuration
public class MqttConfig {

    private static final Logger log = LoggerFactory.getLogger(MqttConfig.class);

    @Autowired
    private MqttConfigProperties configProperties;

    @Autowired
    private MessageHandlerFactory  messageHandlerFactory;

    @Autowired
    private LogConfig logConfig;

    @PostConstruct
    public void initClients() {

        log.info("初始化MQTT客户端, configProperties: {}", JSON.toJSONString(configProperties));

        //1.初始化topicMap，value为TopicConfig对象
        //2.初始化topicClientMap，value为clientId
        configProperties.getDevices().forEach((deviceName, props) -> props.getSubscribeTopics().forEach(topicConfig -> {
            MqttServiceRegistry.registerTopic(topicConfig.getTopic(), topicConfig);
            MqttServiceRegistry.registerTopicDeviceName(topicConfig.getTopic(), deviceName);
        }));

        //3.遍历配置文件中的设备信息，创建客户端
        configProperties.getDevices().forEach((deviceName, props) -> {
            try {
                createClient(deviceName, props);
            } catch (Exception e) {
                log.error("连接MQTT服务器失败, deviceName: {}, props: {}", deviceName, JSON.toJSONString(props), e);
            }
        });


    }


    @PreDestroy
    public void destroy() {
        configProperties.getDevices().forEach((deviceName, props) -> {
            MqttClient client = MqttServiceRegistry.getClient(deviceName);
            if (client != null && client.isConnected()) {
                try {
                    unSubscribeTopics(client, props.getSubscribeTopics());
                    client.disconnect();
                    log.info("已断开MQTT连接: {}", deviceName);
                } catch (MqttException e) {
                    log.error("断开连接失败", e);
                }
            }
        });
    }

    private void createClient(String deviceName, MqttClientProperties props) throws MqttException {
        log.info("创建MQTT客户端, deviceName: {}, props: {}", deviceName, JSON.toJSONString(props));
        String serverURI = props.getProtocol() + "://" + props.getHost() + ":" + props.getPort();

        MqttClient client = new MqttClient(serverURI, props.getClientId());
        MqttConnectOptions options = new MqttConnectOptions();
        options.setAutomaticReconnect(true); // 关键配置：启用自动重连
        options.setCleanSession(false);      // 保持会话，避免订阅丢失
        options.setConnectionTimeout(30);    // 连接超时时间（秒）
        options.setKeepAliveInterval(60);    // 心跳间隔时间（秒）

        // 根据认证类型设置参数
        switch (props.getAuthType()) {
            case BASIC:
                options.setUserName(props.getUsername());
                options.setPassword(props.getPassword().toCharArray());
                break;
            case NONE:
            default:
                // 无认证，不设置任何参数
        }

        // 设置消息监听器
        client.setCallback(new MqttCallbackExtended() {
            @Override
            public void connectComplete(boolean reconnect, String serverURI) {
                // 连接完成回调（包括自动重连）
                log.info("消息客户端连接成功, client: {}, serverURI: {}, 是否为重连: {}", client.getClientId(), serverURI, reconnect);
                // 每次连接成功后都重新订阅主题
                subscribeTopics(client, props.getSubscribeTopics());
            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                if (logConfig.debugLog()){
                    log.info("收到消息, deviceName: {}, topic: {}, message: {}", deviceName, topic, new String(message.getPayload()));
                }

                MqttClientProperties.TopicConfig topicConfig = MqttServiceRegistry.getTopicConfig(topic);
                if (topicConfig == null) {
                    log.error("未找到对应的topic配置, topic: {}", topic);
                    return;
                }

                MessageHandler messageHandler = messageHandlerFactory.getMessageHandler(topicConfig.getTopicType());
                if (messageHandler == null) {
                    log.error("未找到对应的消息处理器, topicType: {}", topicConfig.getTopicType());
                    return;
                }

                messageHandler.handleMessage(deviceName,topicConfig, new String(message.getPayload()));
            }

            @Override
            public void connectionLost(Throwable cause) {
                // 处理连接丢失（记录日志即可，自动重连由Paho处理）
                log.error("消息客户端连接丢失, client: {}, 错误信息: {}", client.getClientId(), cause.getMessage(), cause);
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {
                // 消息发送完成回调（可选）
            }
        });

        client.connect(options);
        MqttServiceRegistry.registerClient(deviceName, client);

    }


    private void subscribeTopics(MqttClient client, List<MqttClientProperties.TopicConfig> topics) {
        if (topics == null || topics.isEmpty()) return;

        String[] topicsArray = new String[topics.size()];
        int[] qosArray = new int[topics.size()];
        for (int i = 0; i < topics.size(); i++) {
            topicsArray[i] = topics.get(i).getTopic();
            qosArray[i] = topics.get(i).getQos();
        }
        try {
            client.subscribe(topicsArray, qosArray);
            log.info("订阅主题成功, topics: {}, qos: {}", JSON.toJSONString(topicsArray), JSON.toJSONString(qosArray));
        } catch (MqttException e) {
            log.error("订阅主题失败, topics: {}, qos: {}", JSON.toJSONString(topicsArray), JSON.toJSONString(qosArray), e);
        }
    }

    private void unSubscribeTopics(MqttClient client, List<MqttClientProperties.TopicConfig> topics) {
        if (topics == null || topics.isEmpty()) return;

        String[] topicsArray = new String[topics.size()];
        for (int i = 0; i < topics.size(); i++) {
            topicsArray[i] = topics.get(i).getTopic();
        }
        try {
            client.unsubscribe(topicsArray);
            log.info("取消订阅主题成功, topics: {}", JSON.toJSONString(topicsArray));
        } catch (MqttException e) {
            log.error("取消订阅主题失败, topics: {}", JSON.toJSONString(topicsArray), e);
        }
    }
}

